package com.movitech.mobile.cz.base.modules.activiti.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.engine.repository.Deployment;
import org.activiti.engine.task.Task;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.movitech.mobile.cz.base.common.utils.DateUtils;
import com.movitech.mobile.cz.base.common.utils.IdGen;
import com.movitech.mobile.cz.base.common.utils.StringUtils;
import com.movitech.mobile.cz.base.modules.activiti.entity.AProcessConfig;
import com.movitech.mobile.cz.base.modules.activiti.entity.AProcessDefinitionConfig;
import com.movitech.mobile.cz.base.modules.activiti.entity.AProcessNodeConfig;
import com.movitech.mobile.cz.base.modules.activiti.entity.AProcessNodeDefinitionConfig;
import com.movitech.mobile.cz.base.modules.activiti.entity.AProcessNodeLineConfig;
import com.movitech.mobile.cz.base.modules.activiti.entity.AProcessNodeLineDefinitionConfig;

@Service
@Transactional
public class ActivitiProcessService{
    protected Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	private ActivitiService activitiService;
	@Autowired
	private AProcessConfigService aProcessConfigService;
	@Autowired
	private AProcessNodeConfigService aProcessNodeConfigService;
	@Autowired
	private AProcessNodeLineConfigService aProcessNodeLineConfigService;
	@Autowired
	private AProcessDefinitionConfigService aProcessDefinitionConfigService;
	@Autowired
	private AProcessNodeDefinitionConfigService aProcessNodeDefinitionConfigService;
	@Autowired
	private AProcessNodeLineDefinitionConfigService aProcessNodeLineDefinitionConfigService;
	
	/***
	 * 根据Activiti流程模板配置对象id，生成Bpmn并部署
	 * @param processConfigId
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackForClassName = { "RuntimeException", "Exception" })
	public Map<String,Object> doGenerateAndDeployBpmByDefinitions(String processDefinitionConfigId,Integer actionType,String filePath) throws Exception {
		Map<String,Object> mapResult = new HashMap<String,Object>();
		Deployment deployment = null;
		boolean isDone = false;
		////
		AProcessConfig aProcessConfig = null;
		List<AProcessNodeConfig> lstAProcessNodeConfig = new ArrayList<AProcessNodeConfig>();
		List<AProcessNodeLineConfig> lstAProcessNodeLineConfig = new ArrayList<AProcessNodeLineConfig>();
		
		Map<String,String> mapDefinitionConfigAndConfig = new HashMap<String,String>();
		AProcessDefinitionConfig aProcessDefinitionConfig = aProcessDefinitionConfigService.getAProcessDefinitionConfigById(processDefinitionConfigId);
		if(aProcessDefinitionConfig!=null) {
			aProcessConfig = new AProcessConfig();
			BeanUtils.copyProperties(aProcessConfig, aProcessDefinitionConfig);
			aProcessConfig.setId(IdGen.uuid());
			aProcessConfig.setCreateDate(DateUtils.getNow());
			aProcessConfig.setUpdateDate(DateUtils.getNow());
			aProcessConfigService.saveAProcessConfig(aProcessConfig);
			
			///
			List<AProcessNodeDefinitionConfig> lstAProcessNodeDefinitionConfig = aProcessNodeDefinitionConfigService.getAProcessNodeDefinitionConfigByProcessDefinitionConfigId(processDefinitionConfigId);
	    	if(!CollectionUtils.isEmpty(lstAProcessNodeDefinitionConfig)) {
	    		for (AProcessNodeDefinitionConfig aProcessNodeDefinitionConfig : lstAProcessNodeDefinitionConfig) {
	    			AProcessNodeConfig aProcessNodeConfig = new AProcessNodeConfig();
	    			BeanUtils.copyProperties(aProcessNodeConfig, aProcessNodeDefinitionConfig);
	    			aProcessNodeConfig.setId(IdGen.uuid());
	    			aProcessNodeConfig.setProcessConfigId(aProcessConfig.getId());
	    			aProcessNodeConfig.setCreateDate(DateUtils.getNow());
	    			aProcessNodeConfig.setUpdateDate(DateUtils.getNow());
	    			aProcessNodeConfigService.saveAProcessNodeConfig(aProcessNodeConfig);
	    			lstAProcessNodeConfig.add(aProcessNodeConfig);
	    			
	    			////
	    			mapDefinitionConfigAndConfig.put(aProcessNodeDefinitionConfig.getId(), aProcessNodeConfig.getId());
				}
	    	}
	    	
			List<AProcessNodeLineDefinitionConfig> lstAProcessNodeLineDefinitionConfig = aProcessNodeLineDefinitionConfigService.getAProcessNodeLineDefinitionConfigByProcessDefinitionConfigId(processDefinitionConfigId);
			if(!CollectionUtils.isEmpty(lstAProcessNodeLineDefinitionConfig)) {
	    		for (AProcessNodeLineDefinitionConfig aProcessNodeLineDefinitionConfig : lstAProcessNodeLineDefinitionConfig) {
	    			AProcessNodeLineConfig aProcessNodeLineConfig = new AProcessNodeLineConfig();
	    			BeanUtils.copyProperties(aProcessNodeLineConfig, aProcessNodeLineDefinitionConfig);
	    			aProcessNodeLineConfig.setId(IdGen.uuid());
	    			aProcessNodeLineConfig.setProcessConfigId(aProcessConfig.getId());
	    			aProcessNodeLineConfig.setFromNodeConfigId(mapDefinitionConfigAndConfig.get(aProcessNodeLineDefinitionConfig.getFromNodeDefinitionConfigId()));
	    			aProcessNodeLineConfig.setToNodeConfigId(mapDefinitionConfigAndConfig.get(aProcessNodeLineDefinitionConfig.getToNodeDefinitionConfigId()));
	    			aProcessNodeLineConfig.setCreateDate(DateUtils.getNow());
	    			aProcessNodeLineConfig.setUpdateDate(DateUtils.getNow());
	    			aProcessNodeLineConfigService.saveAProcessNodeLineConfig(aProcessNodeLineConfig);
	    			lstAProcessNodeLineConfig.add(aProcessNodeLineConfig);
				}
	    	}
			
			////
			if(NumberUtils.toInt(actionType+"") == 1) {
				deployment = doGenerateAndDeployBpm(aProcessConfig, lstAProcessNodeConfig, lstAProcessNodeLineConfig);
				if(deployment!=null) isDone = true;
			}else if(NumberUtils.toInt(actionType+"") == 2) {
				isDone = doGenerateBpmFile(aProcessConfig, lstAProcessNodeConfig, lstAProcessNodeLineConfig, filePath);
			}else if(NumberUtils.toInt(actionType+"") == 3) {
				deployment = doGenerateFileAndDeployBpm(aProcessConfig, lstAProcessNodeConfig, lstAProcessNodeLineConfig, filePath);
				if(deployment!=null) isDone = true;
			}
		}else {
			logger.info("===========com.movitech.mobile.cz.base.modules.activiti.ActivitiProcessService.doGenerateAndDeployBpm====[ERROR]======流程配置不存在");
		}
	
		mapResult.put("deployment", deployment);
		mapResult.put("isDone", isDone);
		return mapResult;
	}
	
	/***
	 * 根据Activiti流程配置对象id，生成Bpmn并部署
	 * @param processConfigId
	 * @return
	 */
    public Deployment doGenerateAndDeployBpm(AProcessConfig aProcessConfig,List<AProcessNodeConfig> lstAProcessNodeConfig,List<AProcessNodeLineConfig> lstAProcessNodeLineConfig) {
    	Deployment deployment = null;
    	try {
        	deployment = activitiService.generateAndDeployBpm(aProcessConfig, lstAProcessNodeConfig, lstAProcessNodeLineConfig);
		} catch (Exception e) {
			logger.info("===========com.movitech.mobile.cz.base.modules.activiti.ActivitiProcessService.doGenerateAndDeployBpmFile====[ERROR]======"+e.getMessage());
			e.printStackTrace();
		}
    	return deployment;
    }
    
    /***
	 * 根据Activiti流程配置对象id、文件路径，生成Bpmn文件
	 * @param processConfigId
	 * @param filePath
	 * @return
	 */
    public boolean doGenerateBpmFile(AProcessConfig aProcessConfig,List<AProcessNodeConfig> lstAProcessNodeConfig,List<AProcessNodeLineConfig> lstAProcessNodeLineConfig,String filePath) {
    	boolean isDone = false;
    	try {
        	isDone = activitiService.generateBpmFile(aProcessConfig, lstAProcessNodeConfig, lstAProcessNodeLineConfig, filePath);
		} catch (Exception e) {
			logger.info("===========com.movitech.mobile.cz.base.modules.activiti.ActivitiProcessService.doGenerateBpmFile====[ERROR]======"+e.getMessage());
			e.printStackTrace();
		}
    	return isDone;
    }
    
    /***
	 * 根据Activiti流程配置对象id，生成Bpmn文件并部署
	 * @param processConfigId
	 * @param filePath
	 * @return
	 */
    public Deployment doGenerateFileAndDeployBpm(AProcessConfig aProcessConfig,List<AProcessNodeConfig> lstAProcessNodeConfig,List<AProcessNodeLineConfig> lstAProcessNodeLineConfig,String filePath) {
    	Deployment deployment = null;
    	try {
        	deployment = activitiService.generateFileAndDeployBpm(aProcessConfig, lstAProcessNodeConfig, lstAProcessNodeLineConfig,filePath);
		} catch (Exception e) {
			logger.info("===========com.movitech.mobile.cz.base.modules.activiti.ActivitiProcessService.doGenerateFileAndDeployBpm====[ERROR]======"+e.getMessage());
			e.printStackTrace();
		}
    	return deployment;
    }
}
